#include "os_event.h"
#include "os_task.h"
#include "os_sched.h"

/**
 * 初始化等待结构
 */
void os_event_wait_init (os_wait_t * wait, os_event_t * event, void * reason, int ms) {
    wait->event = event;
    wait->reason = reason;
    wait->err = OS_ERR_OK;
}

/**
 * 初始化事件结构
 * @param event 事件结构
 * @param type 类型
 * @param flags 初始的标志等
 * @return 初始化结果
*/
os_err_t os_event_init (os_event_t * event, os_event_type_t type, int flags) {
    os_assert(event != OS_NULL);
    os_assert((type >= OS_EVENT_TYPE_INVALID) && (type < OS_EVENT_TYPE_MAX));

	event->type = type;
    event->flags = flags;

    os_list_init(&event->wait_list, os_task_t, event_item);
    return OS_ERR_OK;
}

/**
 * 反初始化化事件结构
 * 当任务再次运行时，其得到的错误码为OS_ERR_REMOVE
 * 
 * @param event 事件结构
 * @return 初始化结果
 */
os_err_t os_event_uninit (os_event_t * event) {
    os_assert(event != OS_NULL);

    os_event_clear(event, OS_NULL, OS_ERR_REMOVE);
    return OS_ERR_OK;
}

/**
 * 将任务从等待队列中移除
*/
void os_event_list_remove (os_event_t * event, os_task_t * task) {
    os_list_remove_item(&event->wait_list, task);

    task->flags &= ~OS_TASK_STATE_WAIT;
    task->event_wait.event = OS_NULL;
}

/**
 * 将任务插入到等待队列
*/
void os_event_list_insert (os_event_t * event, os_task_t * task) {
    task->flags |= OS_TASK_STATE_WAIT;
    task->event_wait.event = event;

#if OS_EVENT_WAIT_PRIO
    // 按优先级排序
    os_list_for_each(cmp_task, os_task_t, &event->wait_list) {
        // 值更大，优先级更低
        if (cmp_task->prio > task->prio) {
            continue;
        }

        // 插入到higher_task之前，可能会作为表头添加
        os_task_t * pre_task = os_list_item_pre(&event->wait_list, cmp_task);
        if (pre_task) {
            os_list_insert_after(&event->wait_list, pre_task, task);
        } else {
            os_list_insert_first(&event->wait_list, task);
        }
        break;
    }

    // 列表为空
    if (cmp_task == OS_NULL) {
        os_list_insert_last(&event->wait_list, task);
    }
#else
    os_list_insert_last(&event->wait_list, task);
#endif
}

/**
 * 让当前任务在事件控制块上等待事件发生
 * @param event 等待的事件
 * @param reason 事件原因
 * @param ms 等待的事件，如果为0将一直超时
 * @return 等待结果
 */
void os_event_wait (os_event_t * event, void * reason, int ms) {
    os_assert(event != OS_NULL);
    os_assert(ms >= 0);
    
    os_task_t * self = os_task_self();

    // 初始化等待事件
    os_event_wait_init(&self->event_wait, event, reason, ms);

    // 从就绪队列移除，加入延时队列
    os_sched_remove_ready(self);
    if (ms > 0) {
        os_sched_set_delay(self, ms);
    }

    // 再插入阻塞队列中
    os_event_list_insert(event, self);
}

/**
 * 唤醒事件控制块中的首个等待的任务
 * @param 等待的事件
 * @param 等待原因
 * @param err 唤醒原因
 * @return 唤醒的任务
*/
os_task_t * os_event_wakeup (os_event_t * event) {
    os_assert(event != OS_NULL);

    os_task_t * task =  (os_task_t *)os_list_first(&event->wait_list);
    if (task == OS_NULL) {
        return OS_NULL;
    }
    os_event_list_remove(event, task);

    // 如果有延时，从延时队列中移除
    if (task->flags & OS_TASK_STATE_DELAYED) {
        os_sched_remove_delay(task);
    }

    // 进入就绪队列
    os_sched_set_ready(task);
    return task;
}

/**
 * 唤醒事件控制块中的指定的任务
 * @param 等待的事件
 * @param 等待原因
 * @param err 唤醒原因
 * @return 唤醒的任务
*/
void os_event_wakeup_task (os_event_t * event, os_task_t * task, void * reason, os_err_t err) {
    os_assert(event != OS_NULL);
    os_assert(task != OS_NULL);
    os_assert(task->event_wait.event == event);

     // 从等待队列中移除
    os_event_list_remove(event, task);

    // 填充结果
    os_wait_t * wait = &task->event_wait;
    wait->err = err;
    wait->reason = reason;

    // 如果有延时，从延时队列中移除
    if (task->flags & OS_TASK_STATE_DELAYED) {
        os_sched_remove_delay(task);
    }

    // 进入就绪队列
    os_sched_set_ready(task);
}

/**
 * 清除所有等待中的任务，将事件发送给所有任务
 * @param event 事件控制块
 * @param reason 清除原因
 * @param err 清除原因
 * @return 有多少个任务被清除掉
*/
void os_event_clear (os_event_t * event, void * reason, os_err_t err) {
    os_assert(event != OS_NULL);
    
    os_task_t * task;

    while ((task = (os_task_t *)os_list_first(&event->wait_list)) != OS_NULL) {
        // 如果有延时，从延时队列中移除
        if (task->flags & OS_TASK_STATE_DELAYED) {
            os_sched_remove_delay(task);
        }

        os_event_list_remove(event, task);

        // 设置任务事件
        task->event_wait.err = err;
        task->event_wait.reason = reason;

        // 进入就绪队列
        os_sched_set_ready(task);
    }
}

/**
 * 获取等待队列中任务的数量
 * @param event 事件控制块
 */
int os_event_wait_cnt (os_event_t * event) {
    os_assert(event != OS_NULL);
    return os_list_count(&event->wait_list);
}  



